package com.nuoniu.sibanyun.service.erp.barcode.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.entity.dto.ErpBarcodePrintSearchDto;
import com.nuoniu.sibanyun.entity.erp.barcode.*;
import com.nuoniu.sibanyun.entity.vo.ErpBarcodeRuleContentVo;
import com.nuoniu.sibanyun.mapper.erp.barcode.ErpBarcodePrintMapper;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherTableService;
import com.nuoniu.sibanyun.service.erp.barcode.*;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 * 条码管理-打印 服务实现类
 * </p>
 *
 * @author 白强
 * @since 2021-11-10
 */
@Service
public class ErpBarcodePrintServiceImpl extends ServiceImpl<ErpBarcodePrintMapper, ErpBarcodePrint> implements IErpBarcodePrintService {

    @Autowired
    private IErpBarcodeRuleService barcodeRuleService;
    @Autowired
    private IErpBarcodeRuleContentService barcodeRuleContentService;
    @Autowired
    private IErpVoucherTableService erpVoucherTableService;
    @Autowired
    private IErpVoucherDesignService erpVoucherDesignService;
    @Autowired
    private IErpAccountService accountService;
    @Autowired
    private IErpBarcodeMainInfoService barcodeMainInfoService;
    @Autowired
    private IErpBarcodePrintDetailService barcodePrintDetailService;
    @Autowired
    private IErpBarcodePrintSourceService barcodePrintSourceService;




    @Override
    public Page<ErpBarcodePrint> pageErpBarcodePrint(Page page, ErpBarcodePrintSearchDto barcodePrintSearchDto) {
        UserInfo userInfo = UserThreadLocal.get();
        Page<ErpBarcodePrint> erpBarcodePrintPage = baseMapper.pageErpBarcodePrint(page, userInfo.getCompanyId(), barcodePrintSearchDto);
        return erpBarcodePrintPage;
    }

    /**
     * 生成条码 (保存)
     * @param erpBarcodePrint
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Long generateBarcode( ErpBarcodePrint erpBarcodePrint) {
        /** 1：合并生单  2：逐行生单 3：保存更新 */
        Integer actionType = erpBarcodePrint.getActionType();
        Integer currentAccountId = accountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        List<ErpBarcodePrintSource> printSources = erpBarcodePrint.getPrintSources();

        Integer barcodeRuleId = erpBarcodePrint.getBarcodeRuleId();
        String voucherTypeCode = erpBarcodePrint.getVoucherTypeCode();
        if(null == barcodeRuleId)throw new NuoNiuException("请选择条码规则");
        Long mainId = erpBarcodePrint.getId();
        if(null != mainId){
            List<ErpBarcodePrintDetail> oldPrintDetails = erpBarcodePrint.getPrintDetails();
            if(null == oldPrintDetails || oldPrintDetails.size() == 0)throw new NuoNiuException("条码明细不能为空");
            if ( oldPrintDetails.stream().anyMatch(f-> null == f.getId()) )throw new NuoNiuException("参数错误");
            oldPrintDetails = oldPrintDetails.stream().map(item->{
                ErpBarcodePrintDetail detail = new ErpBarcodePrintDetail();
                detail.setId(item.getId());
                detail.setPrintQuantity(item.getPrintQuantity());
                detail.setQuantity(item.getQuantity());
                return detail;
            }).collect(Collectors.toList());
            barcodePrintDetailService.saveOrUpdateBatch(oldPrintDetails);
        }else{
            /** 保存条码打印主表 */
            erpBarcodePrint.setCompanyId(userInfo.getCompanyId());
            erpBarcodePrint.setAccountId(currentAccountId);
            boolean b = saveOrUpdate(erpBarcodePrint);
            int erpBarcodePrintId = erpBarcodePrint.getId().intValue();
            ErpBarcodeRule barcodeRule = barcodeRuleService.getById(barcodeRuleId);
            //条码类型
            Integer barcodeType = barcodeRule.getBarcodeType();
            //规则类型 1:主档对照 2：动态解释
            Integer ruleType = barcodeRule.getRuleType();
            //校验 源单明细 不能为空
            if(null == printSources || printSources.size() == 0)throw new NuoNiuException("源单明细不能为空");
            boolean isNoQuantity  = printSources.stream().anyMatch(item -> null == item.getExpectedPrintQuantity() || !(item.getExpectedPrintQuantity() > 0));
            if(isNoQuantity)throw new NuoNiuException("请填写原单明细的预计打印数量");
            /** 获取 规则内容 */
            List<ErpBarcodeRuleContentVo> erpBarcodeRuleContentVos = barcodeRuleContentService.listErpBarcodeRuleContentVo(barcodeRuleId.longValue(),voucherTypeCode);
            if(erpBarcodeRuleContentVos.size() == 0)throw new NuoNiuException("规则与适用对象不匹配");
            if(erpBarcodeRuleContentVos.stream().noneMatch(f->null != f.getIsCode() && f.getIsCode()))throw new NuoNiuException("请设置参与编码的属性");
            if(erpBarcodeRuleContentVos.size() == 0)throw new NuoNiuException("保存失败，获取规则内容错误");
            List<Integer> detailIds = new ArrayList<>();
            List<Integer> voucherDesignIds = new ArrayList<>();
            Map<Integer,ErpBarcodePrintSource> printSourceMap = new HashMap<>();
            Map<Integer,String> barcodeMap = new HashMap<>();
            erpBarcodeRuleContentVos.forEach(item-> voucherDesignIds.add(item.getVoucherFieldId()));
            printSources.forEach(item->{
                detailIds.add(item.getSourceDetailId());
                printSourceMap.put(item.getSourceDetailId(),item);
            });
            if(detailIds.size() == 0)throw new NuoNiuException("请设置好条码属性的对应字段");
            /** 获取 源单据明细 所对应的 规则内容 */
            List<HashMap<String, Object>> specifyFieldRecord = erpVoucherDesignService.getSpecifyFieldRecord(detailIds, voucherDesignIds, voucherTypeCode);
            List<ErpBarcodePrintDetail> printDetails = new ArrayList<>();
            Map<String,List<String>> moreBarcodeMap = new HashMap<>();
            Map<String,String> dynamicAnalysisJsonMap = new HashMap<>();
            //更新源单 逐条解析  生产 条码
            specifyFieldRecord.forEach(record->{
                ErpBarcodePrintDetail erpBarcodePrintDetail = new ErpBarcodePrintDetail();
                StringBuffer barcodeBuffer = new StringBuffer();
                //动态解析JSON
                String dynamicAnalysisJson = JSON.toJSONString(record);

                /** 组装 条码 */
                erpBarcodeRuleContentVos.forEach(item->{
                    if(null != item.getIsCode() && item.getIsCode()){
                        barcodeBuffer.append(record.get(item.getCode()));
                        if(StringUtils.isNotBlank(item.getSeparatorChar())){
                            barcodeBuffer.append(item.getSeparatorChar());
                        }

                    }
                });
                String barcode = barcodeBuffer.toString();
                /** 设置 条码明细 */
                erpBarcodePrintDetail.setBarCode(barcode);
                erpBarcodePrintDetail.setCompanyId(userInfo.getCompanyId());
                erpBarcodePrintDetail.setAccountId(currentAccountId);
                erpBarcodePrintDetail.setBarcodePrintId(erpBarcodePrintId);
                erpBarcodePrintDetail.setBarcodeRuleId(erpBarcodePrint.getBarcodeRuleId());
                erpBarcodePrintDetail.setBarcodeRuleCode(erpBarcodePrint.getBarcodeRuleCode());
                erpBarcodePrintDetail.setBarcodeRuleName(erpBarcodePrint.getBarcodeRuleName());
                /** 设置 动态解析JSON */
                erpBarcodePrintDetail.setExtendJson(dynamicAnalysisJson);
                dynamicAnalysisJsonMap.put(barcode,dynamicAnalysisJson);
                erpBarcodePrintDetail.setIsMainInfo(ruleType == 1);
                Object sourceDetailIdObj = record.get("sourceDetailId");
                if(null != sourceDetailIdObj){
                    Integer sourceDetailId = Integer.valueOf(sourceDetailIdObj.toString());
                    barcodeMap.put(sourceDetailId,barcode);
                    ErpBarcodePrintSource erpBarcodePrintSource = printSourceMap.get(sourceDetailId);
                    if(null != erpBarcodePrintSource){
                        erpBarcodePrintDetail.setInventoryId(erpBarcodePrintSource.getInventoryId());
                        erpBarcodePrintDetail.setInventoryName(erpBarcodePrintSource.getInventoryName());
                        erpBarcodePrintDetail.setInventoryCode(erpBarcodePrintSource.getInventoryCode());
                        erpBarcodePrintDetail.setInventorySpecification(erpBarcodePrintSource.getInventorySpecification());
                        erpBarcodePrintDetail.setQuantity(erpBarcodePrintSource.getQuantity());
                        erpBarcodePrintDetail.setPrintQuantity(erpBarcodePrintSource.getExpectedPrintQuantity());
                        erpBarcodePrintDetail.setCumPrintQuantity(erpBarcodePrintSource.getExpectedPrintQuantity());
                        // todo 设置状态
//                        erpBarcodePrintDetail.setStatus()
                    }
                }

                List<String> moreBarCodeList = new ArrayList<>();
                /**  1：合并生单  2：逐行生单 3：保存更新  */
                if(1 == actionType){
                    erpBarcodePrintDetail.setPrintQuantity(1);
                    erpBarcodePrintDetail.setCumPrintQuantity(1);
                    printDetails.add(erpBarcodePrintDetail);
                }else if(2 == actionType){

                    Integer printQuantity = erpBarcodePrintDetail.getPrintQuantity();
                    erpBarcodePrintDetail.setPrintQuantity(1);
                    erpBarcodePrintDetail.setCumPrintQuantity(1);
                    for (int i = 0; i < printQuantity; i ++){
                        if(3 == barcodeType){
                            String newBarcode = barcode + "-" + i;
                            ErpBarcodePrintDetail cloneErpBarcodePrintDetail = new ErpBarcodePrintDetail();
                            BeanUtils.copyProperties(erpBarcodePrintDetail,cloneErpBarcodePrintDetail);
                            cloneErpBarcodePrintDetail.setBarCode(newBarcode);
                            printDetails.add(cloneErpBarcodePrintDetail);
                            moreBarCodeList.add(newBarcode);
                        }else{
                            printDetails.add(erpBarcodePrintDetail);
                        }
                   }
                }
                moreBarcodeMap.put(barcode,moreBarCodeList);
            });
            /*************  规则类型 1:主档对照 2：动态解释  ************/
            if(1 == ruleType){
                /** 从源单明细 拉去数据 到 条码主档信息 */
                List<ErpBarcodeMainInfo> erpBarcodeMainInfos = erpVoucherDesignService.listByVoucherTable(detailIds, voucherTypeCode);
                Map<String,ErpBarcodeMainInfo> ErpBarcodeMainInfoMap = new HashMap<>();
                List<ErpBarcodeMainInfo>  moreErpBarcodeMainInfoList = new ArrayList<>();
                erpBarcodeMainInfos = erpBarcodeMainInfos.stream().filter(info->{
                    Integer sourceDetailId = info.getSourceDetailId();
                    String barcode = barcodeMap.get(sourceDetailId);
                    if( ErpBarcodeMainInfoMap.containsKey(barcode)){
                        return false;
                    }
                    ErpBarcodeMainInfoMap.put(barcode,info);
                    String extendJson = dynamicAnalysisJsonMap.get(barcode);
                    info.setBarCode(barcode);
                    info.setExtendJson(extendJson);
                    info.setCompanyId(userInfo.getCompanyId());
                    info.setAccountId(currentAccountId);
                    info.setBarcodeRuleId(erpBarcodePrint.getBarcodeRuleId());
                    info.setBarcodeRuleName(erpBarcodePrint.getBarcodeRuleName());
                    info.setAccountId(erpBarcodePrint.getAccountId());
                    info.setCompanyId(erpBarcodePrint.getCompanyId());
                    //3.序列号 条码 按数量依次生成
                    if(3 == barcodeType){
                        List<String> moreBarcodes = moreBarcodeMap.get(barcode);
                        moreBarcodes.forEach(newBarcode->{
                            ErpBarcodeMainInfo newErpBarcodeMainInfo = new ErpBarcodeMainInfo();
                            BeanUtils.copyProperties(info,newErpBarcodeMainInfo);
                            newErpBarcodeMainInfo.setBarCode(newBarcode);
                            moreErpBarcodeMainInfoList.add(newErpBarcodeMainInfo);
                        });
                    }
                    return true;
                }).collect(Collectors.toList());
                /** 新增额外的条码主档 */
                if(moreErpBarcodeMainInfoList.size() > 0){
                    erpBarcodeMainInfos.addAll(moreErpBarcodeMainInfoList);
                }
                /** 保存 条码主档 */
                boolean saveMainInfoBatch = barcodeMainInfoService.saveBatch(erpBarcodeMainInfos);
                if(saveMainInfoBatch){
                    erpBarcodeMainInfos.forEach(info->{
                        Integer sourceDetailId = info.getSourceDetailId();
                        String barcode = barcodeMap.get(sourceDetailId);
                        printDetails.stream().filter(printDetail->printDetail.getBarCode().equals(barcode)).forEach(printDetail->printDetail.setBarcodeMainInfoId(info.getId().intValue()));
                    });
                }
            }
            /** 保存 源单明细 */
            barcodePrintSourceService.saveBatch(printSources);
            /** 保存 条码明细 */
            barcodePrintDetailService.saveBatch(printDetails);
        }
        return erpBarcodePrint.getId();
    }

    @Override
    public ErpBarcodePrint detailById(Long id) {
        if(null == id)throw new NuoNiuException("参数错误");
        ErpBarcodePrint barcodePrint = getById(id);
        List<ErpBarcodePrintSource> erpBarcodePrintSources = barcodePrintSourceService.listByPrintId(id);
        barcodePrint.setPrintSources(erpBarcodePrintSources);
        List<ErpBarcodePrintDetail> erpBarcodePrintDetails = barcodePrintDetailService.listByPrintId(id);
        barcodePrint.setPrintDetails(erpBarcodePrintDetails);
        return barcodePrint;
    }


}
